package bold.storage.component;


import bold.storage.splice.SqlKit;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

public class Where {
    private boolean isOr = false;
    private StringBuilder sql = new StringBuilder();
    private ArrayList<Object> param = new ArrayList<>();

    Where() {
    }

    Where(boolean isOr) {
        this.isOr = isOr;
    }

    Where(String key, String value) {
        this.eq(key, value);
    }

    Where(Map<String, String> map) {
        map.forEach(this::eq);
    }

    Where(String sql, String... values) {
        this.sql.append(sql);
        this.param.addAll(Arrays.asList(values));
    }

    public String sql() {
        return this.sql.length() > 1 ? " where " + this.sql.toString() : " where 1";
    }

    public ArrayList<Object> param() {
        return this.param;
    }

    public Where eq(String key, String value) {
        if (isL(value)) return this;
        this.param.add(value);
        return this.addRule(key, " = ? ");
    }

    public Where eq(String key, Object value) {
        this.param.add(value);
        return this.addRule(key, " = ? ");
    }

    public Where like(String key, String value) {
        if (isL(value)) return this;
        this.param.add("%" + String.valueOf(value) + "%");
        return this.addRule(key, " like ? ");
    }

    public Where leftLike(String key, String value) {
        if (isL(value)) return this;
        this.param.add(value + "%");
        return this.addRule(key, " like ? ");
    }

    public Where bt(String key, String value) {
        if (isL(value)) return this;
        this.param.add(value);
        return this.addRule(key, " > ? ");
    }

    public Where lt(String key, String value) {
        if (isL(value)) return this;
        this.param.add(value);
        return this.addRule(key, " < ? ");
    }

    public Where be(String key, String value) {
        if (isL(value)) return this;
        this.param.add(value);
        return this.addRule(key, " >= ? ");
    }

    public Where le(String key, String value) {
        if (isL(value)) return this;
        this.param.add(value);
        return this.addRule(key, " <= ? ");
    }

    public Where ne(String key, String value) {
        if (isL(value)) return this;
        this.param.add(value);
        return this.addRule(key, " != ? ");
    }

    public Where isNull(String key) {
        return this.addRule(key, " is null ");
    }

    public Where notNull(String key) {
        return this.addRule(key, " is not null ");
    }

    public Where in(String key, Query query) {
        this.param.addAll(Arrays.asList(query.param()));
        return this.addRule(key, " in " + SqlKit.wrapCurve(query.sql()));
    }

    public Where in(String key, Long... longs) {
        if (longs.length == 0) return this;
        return this.in(key, Arrays.asList(longs));
    }

    public Where in(String key, String... str) {
        if (isL(str)) return this;
        return this.in(key, Arrays.asList(str));
    }

    public Where in(String key, List<?> list) {
        if (isL(list)) return this;
        String part = SqlKit.concatPlaceholder(list.size());
        this.param.addAll(list);
        return this.addRule(key, " in " + SqlKit.wrapCurve(part));
    }

    private Where addRule(String key, String rule) {
        if (this.sql.length() > 0) {
            this.sql.append(SqlKit.wrapBlank(this.isOr ? "or" : "and"));
        }

        this.sql.append(SqlKit.wrapCol(key)).append(rule);
        return this;
    }

    StringBuilder getSql() {
        return this.sql;
    }

    public Where or(Where where) {
        if (this.sql.length() != 0) this.sql.append(" or ");
        this.sql.append(SqlKit.wrapCurve(where.getSql()));
        this.param.addAll(where.param());
        return this;
    }

    public Where and(Where where) {
        if (this.sql.length() != 0) this.sql.append(" and ");
        this.sql.append(SqlKit.wrapCurve(where.getSql()));
        this.param.addAll(where.param());
        return this;
    }

    public Where add(String sql, Object... values) {
        if (this.sql.length() > 0) {
            this.sql.append(SqlKit.wrapBlank(this.isOr ? "or" : "and"));
        }

        this.sql.append(SqlKit.wrapBlank(sql));
        this.param.addAll(Arrays.asList(values));
        return this;
    }


    private boolean isL(String v) {
        if (v == null || "".equals(v)) return true;
        return false;
    }

    private boolean isL(String v1, String v2) {
        if (v1 == null || "".equals(v1) || v2 == null || "".equals(v2)) return true;
        return false;
    }

    private boolean isL(String[] str) {
        if (str == null || str.length == 0) return true;
        return false;
    }

    private boolean isL(List list) {
        if (list == null || list.isEmpty()) return true;
        return false;
    }
}
